// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//
#include <pollux/functions/registerer.h>
#include <pollux/functions/lib/registration_helpers.h>
#include <pollux/functions/prestosql/arithmetic.h>
#include <pollux/functions/prestosql/decimal_functions.h>
#include <pollux/functions/prestosql/rand.h>

namespace kumo::pollux::functions {
    namespace {
        void registerTruncate(const std::vector<std::string> &names) {
            register_function<TruncateFunction, double, double>(names);
            register_function<TruncateFunction, float, float>(names);
            register_function<TruncateFunction, double, double, int32_t>(names);
            register_function<TruncateFunction, float, float, int32_t>(names);
        }

        void registerMathFunctions(const std::string &prefix) {
            registerUnaryNumeric<CeilFunction>({prefix + "ceil", prefix + "ceiling"});
            registerUnaryNumeric<FloorFunction>({prefix + "floor"});

            registerUnaryNumeric<AbsFunction>({prefix + "abs"});
            register_function<
                DecimalAbsFunction,
                LongDecimal<P1, S1>,
                LongDecimal<P1, S1> >({prefix + "abs"});
            register_function<
                DecimalAbsFunction,
                ShortDecimal<P1, S1>,
                ShortDecimal<P1, S1> >({prefix + "abs"});

            registerUnaryFloatingPoint<NegateFunction>({prefix + "negate"});
            register_function<NegateFunction, LongDecimal<P1, S1>, LongDecimal<P1, S1> >(
                {prefix + "negate"});
            register_function<NegateFunction, ShortDecimal<P1, S1>, ShortDecimal<P1, S1> >(
                {prefix + "negate"});

            register_function<RadiansFunction, double, double>({prefix + "radians"});
            register_function<DegreesFunction, double, double>({prefix + "degrees"});
            registerUnaryNumeric<RoundFunction>({prefix + "round"});
            register_function<RoundFunction, int8_t, int8_t, int32_t>({prefix + "round"});
            register_function<RoundFunction, int16_t, int16_t, int32_t>(
                {prefix + "round"});
            register_function<RoundFunction, int32_t, int32_t, int32_t>(
                {prefix + "round"});
            register_function<RoundFunction, int64_t, int64_t, int32_t>(
                {prefix + "round"});
            register_function<RoundFunction, double, double, int32_t>({prefix + "round"});
            register_function<RoundFunction, float, float, int32_t>({prefix + "round"});
            register_function<PowerFunction, double, double, double>(
                {prefix + "power", prefix + "pow"});
            register_function<PowerFunction, double, int64_t, int64_t>(
                {prefix + "power", prefix + "pow"});
            register_function<ExpFunction, double, double>({prefix + "exp"});
            register_function<ClampFunction, int8_t, int8_t, int8_t, int8_t>(
                {prefix + "clamp"});
            register_function<ClampFunction, int16_t, int16_t, int16_t, int16_t>(
                {prefix + "clamp"});
            register_function<ClampFunction, int32_t, int32_t, int32_t, int32_t>(
                {prefix + "clamp"});
            register_function<ClampFunction, int64_t, int64_t, int64_t, int64_t>(
                {prefix + "clamp"});
            register_function<ClampFunction, double, double, double, double>(
                {prefix + "clamp"});
            register_function<ClampFunction, float, float, float, float>(
                {prefix + "clamp"});
            register_function<LnFunction, double, double>({prefix + "ln"});
            register_function<Log2Function, double, double>({prefix + "log2"});
            register_function<Log10Function, double, double>({prefix + "log10"});
            register_function<SqrtFunction, double, double>({prefix + "sqrt"});
            register_function<CbrtFunction, double, double>({prefix + "cbrt"});
            register_function<
                WidthBucketFunction,
                int64_t,
                double,
                double,
                double,
                int64_t>({prefix + "width_bucket"});

            registerUnaryNumeric<SignFunction>({prefix + "sign"});
            register_function<InfinityFunction, double>({prefix + "infinity"});
            register_function<IsFiniteFunction, bool, double>({prefix + "is_finite"});
            register_function<IsInfiniteFunction, bool, double>({prefix + "is_infinite"});
            register_function<IsNanFunction, bool, double>({prefix + "is_nan"});
            register_function<NanFunction, double>({prefix + "nan"});
            register_function<RandFunction, double>({prefix + "rand", prefix + "random"});
            registerUnaryIntegral<RandFunction>({prefix + "rand", prefix + "random"});
            register_function<SecureRandFunction, double>(
                {prefix + "secure_rand", prefix + "secure_random"});
            registerBinaryNumeric<SecureRandFunction>(
                {prefix + "secure_rand", prefix + "secure_random"});
            register_function<FromBaseFunction, int64_t, Varchar, int64_t>(
                {prefix + "from_base"});
            register_function<ToBaseFunction, Varchar, int64_t, int64_t>(
                {prefix + "to_base"});
            register_function<PiFunction, double>({prefix + "pi"});
            register_function<EulerConstantFunction, double>({prefix + "e"});

            registerTruncate({prefix + "truncate"});

            register_function<
                CosineSimilarityFunction,
                double,
                Map<Varchar, double>,
                Map<Varchar, double> >({prefix + "cosine_similarity"});
        }
    } // namespace

    void registerMathematicalFunctions(const std::string &prefix = "") {
        registerMathFunctions(prefix);
        POLLUX_REGISTER_VECTOR_FUNCTION(udf_not, prefix + "not");

        registerDecimalFloor(prefix);
        registerDecimalRound(prefix);
        registerDecimalTruncate(prefix);
    }
} // namespace kumo::pollux::functions
